package dsx.netServer;

import java.util.LinkedList;
import java.util.Queue;

import dsx.console.DsxConsole;
import dsx.log.ServLog;
import dsx.system.ThreadEx;

class TCPChannelTable extends ThreadEx {
	Queue<Integer> freeSock;
	TCPChannelHandler[] table;
	int maxConNum = 65536;
	int nextPos = 0;
	int loop = 200;

	public TCPChannelTable(int maxConNum, int timeout) {
		this.maxConNum = maxConNum;
		this.table = new TCPChannelHandler[maxConNum];
		for (int i = 0; i < maxConNum; i++) {
			this.table[i] = null;
		}
		this.freeSock = new LinkedList<Integer>();
		this.timeout = timeout;
		this.perLoopNum = this.maxConNum / this.timeout;
		if (this.perLoopNum < 1000)
			this.perLoopNum = 1000;
	}

	public boolean add(TCPChannelHandler handler) {
		synchronized (this) {
			int index = 0, loop = 0, pos = 0;
			if (this.freeSock.size() > 0) {
				index = this.freeSock.poll().intValue();
				pos = index % this.maxConNum;
				loop = index / this.maxConNum + 1;
				if (loop >= 200)
					loop = 0;
				DsxConsole.out(String.format("reuse pos %d", pos), "net server handler table add",
						ServLog.info);
			} else if (this.nextPos < this.maxConNum) {
				pos = this.nextPos;
				this.nextPos++;
			} else {
				return false;
			}
			this.table[pos] = handler;
			handler.setChannelId(loop * this.maxConNum + pos);
			DsxConsole.out(String.format("channel %d", handler.getChannelId()), "net server handler table add",
					ServLog.info);
			return true;
		}
	}

	public void remove(TCPChannelHandler handler) {
		synchronized (this) {
			int pos = handler.getChannelId() % this.maxConNum;
			if (this.table[pos] != null) {
				if (this.table[pos].getChannelId() == handler.getChannelId()) {
					DsxConsole.out(Integer.toString(this.table[pos].getChannelId()), "net server handler table remove",
							ServLog.info);
					this.freeSock.offer(new Integer(handler.getChannelId()));
					this.table[pos] = null;
				}
			}
		}
	}

	// 以下是超时检测

	int ticks = 0;
	final int tickMax = 1000000000;
	int timeout;
	int perLoopNum = 1000;
	int loopIndex = 0;

	public int getTick() {
		return this.ticks;
	}

	@Override
	protected void doInLoop() {
		try {
			ThreadEx.sleepEx(1000);
			synchronized (this) {
				int cnt = 0;
				while (cnt < this.perLoopNum && this.loopIndex < this.maxConNum) {
					if (this.table[this.loopIndex] != null) {
						try {
							if (this.ticks >= this.table[this.loopIndex]
									.getLastCommTime()) {
								if (this.ticks
										- this.table[this.loopIndex]
												.getLastCommTime() >= this.timeout) {
									this.table[this.loopIndex].close();
								}
							} else if (this.tickMax
									+ this.ticks
									- this.table[this.loopIndex]
											.getLastCommTime() >= this.timeout) {
								this.table[this.loopIndex].close();
							}
						} catch (Exception ex) {
							DsxConsole.out(ex.getMessage(), "net server table loop 1", ServLog.error);
						}
					}
					cnt++;
					this.loopIndex++;
				}
				if (this.loopIndex >= this.maxConNum)
					this.loopIndex = 0;
			}
		} catch (Exception ex) {
			DsxConsole.out(ex.getMessage(), "net server table loop 2", ServLog.error);
		}
		this.ticks++;
		if (this.ticks >= this.tickMax)
			this.ticks = 0;
	}

}
